﻿#include "CsvReader.h"
#include "Utils.h"
#define ZERO ((unsigned int) 0)


void readCsv( Value& value, const char* filePath )
{
	unsigned long size = 0;
	char* content = (char *)CCFileUtils::sharedFileUtils()->getFileData(filePath, "r", &size);

	string str(content, size);
	int pos = 0;
	while(str.size() > 0) {
		int offsetLen = -1;
		if((pos = str.find("\r\n")) > 0) {
			offsetLen = 2;
		}

		if(offsetLen == -1 && (pos = str.find("\n")) > 0) {
			offsetLen = 1;
		}

		if(offsetLen == -1) {
			break;
		}
		string line = str.substr(0, pos);
		str = str.substr(pos + offsetLen);
		Value lineValue ;
		handleLine(lineValue,line);
		if(lineValue != NULL && !lineValue.isNull()) {
			value[value.size()] = lineValue;
		}
	}
    
    CC_SAFE_DELETE_ARRAY(content);
}

void handleLine(Json::Value& row, string line )
{
	line = trimstr(line);
	if(line.find_first_of('#') == 0 || line.find_first_of("\"#") == 0 || line.size() == 0) {
		return ;
	}
	line = line + ",";
	int linestart = 0;
	bool match = false;
	while ((linestart = findNextVaildChar(line, match)) != string::npos)
	{
		string content = (match && linestart - 2 > 1) ? line.substr(1, linestart - 2) : line.substr(0, linestart);
		content = replace_all_distinct(content, "\\n", "\n");
		row[row.size()] = content.c_str();
		linestart += 1;
		line = line.substr(linestart);

	}
}

Value* arrayToMapping( Value& content )
{
	if(content.size() < 2 || checkKeys(content)) {
		return NULL;
	}
	Value* mapping = new Value;
	Value fieldtype = content[ZERO];
	Value fieldname = content[1];
	Reader reader;
	for(unsigned int i = 2; i < content.size(); i++) {
		Value row;
		for(unsigned int j = 0; j < fieldname.size(); j++) { 
			if(fieldtype[j] == "int") {
				string str =  content[i][j].asString();
				row[fieldname[j].asString()] = atoi(str.c_str());
			} else if(fieldtype[j] == "object") {
				Value object;
				reader.parse(content[i][j].asCString(), object, false);
				if(object.isNull()) {
					reader.parse("{}", object, false);
				}
				row[fieldname[j].asString()] = object; 
			} else if(fieldtype[j] == "array") {
				Value array;
				if(!reader.parse(content[i][j].asCString(), array, true));
				if(array.isNull()) {
					reader.parse("[]", array, false);
				}
				row[fieldname[j].asString()] = array; 
			} else {
				row[fieldname[j].asString()] = content[i][j].asString(); 
			}
		}

		if(fieldtype[ZERO] == "int") {
			(*mapping)[row[fieldname[ZERO].asString()].asInt()] = row;
		} else {
			(*mapping)[row[fieldname[ZERO].asString()].asString()] = row;  
		}
	}
	return mapping;
}

Value* arrayToMapping( const char* filePath )
{
	Value value;
	readCsv(value,filePath);
	return arrayToMapping(value);
}

bool checkKeys( Value& content )
{
	if(content.size() < 2) {
		return false;
	}

	Value value;
	for(unsigned int i = 3; i < content.size(); i++) { 
		value[i - 2] = content[i][1];
	}

	Value keysMap;
	for(unsigned int i = 1; i < value.size(); i++) {
		if(keysMap.get(i, NULL) == NULL) {
			keysMap[i] = true;
		} else {
			CCLOG("key重复");
			return true;
		}
	}
	return false;

}

int findNextVaildChar( string content, bool& match )
{
	int tmpPos = 0;
	match = false;
	if((tmpPos = content.find_first_of("\"")) == 0) {
		match = true;
		int quote = 1;
		int nextQuote = 0;
		int nextComma = 0;
		while(true) {
			nextQuote = content.find_first_of("\"", nextQuote + 1);
			if(nextQuote != string::npos && nextQuote < content.size()) {
				++quote;
			} else {
				return string::npos;
			}
			if(quote % 2 == 0) {
				nextComma = content.find_first_of(",", nextQuote + 1);
				nextQuote = content.find_first_of("\"", nextQuote + 1);
				if(nextQuote == string::npos) {
					return nextComma;
				}
				if(nextComma < nextQuote) {
					return nextComma;
				}
				quote++;
			}
		}
	} else if((tmpPos = content.find_first_of("[")) == 0) {
		tmpPos = content.find_first_of("]");
		if(tmpPos == string::npos) {
			return string::npos;
		}
		return content.find_first_of(",", tmpPos + 1);
	} else if((tmpPos = content.find_first_of("{")) == 0) {
		tmpPos = content.find_first_of("}");
		if(tmpPos == string::npos) {
			return string::npos;
		}
		return content.find_first_of(",", tmpPos + 1);
	} 
	return content.find_first_of(",");
}


